package org.dei.perla.utils;

import org.dei.perla.utils.fsm.StateHandler;
import org.dei.perla.utils.fsm.StateMachineEvent;
import org.dei.perla.utils.fsm.TransactionAction;


public abstract class StateMachine implements Runnable{
	
	public static final int EVENT_IGNORED = 0;
	public static final int EVENT_HANDLED = 1;
	public static final int EVENT_CHANGED = 2;
	
	public static final int INIT_CODE	= 0x0000;
	public static final int EXIT_CODE	= 0x0001;
	public static final int ENTRY_CODE	= 0x0002;
	
	public static final StateMachineEvent<Object> initEvent = new StateMachineEvent<Object>(INIT_CODE, null);
	public static final StateMachineEvent<Object> exitEvent = new StateMachineEvent<Object>(EXIT_CODE, null);
	public static final StateMachineEvent<Object> entryEvent = new StateMachineEvent<Object>(ENTRY_CODE, null);
	
	@SuppressWarnings("unchecked")
	private StateHandler  state;
	
	public TransactionAction passageAction;

	public <E> void onInit(StateHandler<E> initState){
		stateChange(initState, null);
		dispatcher(initEvent);
	}
	
	public <E> void onInit(StateHandler<E> initState, StateMachineEvent<E> event){
		stateChange(initState, null);
		dispatcher(event);
	}
	
	@SuppressWarnings("unchecked")
	public <E> void dispatcher(StateMachineEvent<E> event){
		StateHandler<E> previousState = (StateHandler<E>) this.state;
		int outcome = this.state.exec(this, event);
		if ((outcome == EVENT_HANDLED) || (outcome == EVENT_IGNORED))
			return;
		else{
			previousState.exec(this, (StateMachineEvent<E>) exitEvent);
			if(this.passageAction != null)
				this.passageAction.doTransaction(this);
			this.state.exec(this, entryEvent);
		}
	}
	
	@SuppressWarnings("unchecked")
	protected synchronized int stateChange(StateHandler newState, TransactionAction newTransaction){
		this.state = newState;
		this.passageAction = newTransaction;
		return EVENT_CHANGED;
	}
	
}
